import json
from sys import flags

import allure
import jsonpath
import requests.models
from Common.connect import ConnectMysql
from Common.yaml_opertion import YamlOpertion
from Common.log_opertion import logs
class Assertions:
    """
    五种模式
    1.字符串包含
    2.结果相等断言
    3.结果不相等断吉
    4.断吉接口返回值里面的任意一个值
    5.数摇库断言
    """
    def __init__(self):
        self.logs=logs
        self.consql=ConnectMysql()

    def validations(self,validation:list,response:requests.models.Response):
        # 断言标识flag
        flag = 0
        try:
            if not isinstance(validation,list):
                flag+=1
                self.logs.error('validation用例必须使用列表格式!本次返回None')
                assert flag==0
            if not isinstance(response, dict):
                response=dict(response.json())

            for validate_dict in validation:
                # validate_dict--->{'contains': {'msg': '登陆成功'}}
                for validate,expect in validate_dict.items():
                    # validate-->contains   expect-->{'msg': '登陆成功'}
                    if validate=='contains':
                        flag+=self.contains(expect=expect,response=response)
                    elif validate=='equals':
                        flag += self.equals(expect=expect, response=response)
                    elif validate=='unequals':
                        flag += self.unequals(expect=expect, response=response)
                    elif validate=='db':
                        flag += self.assert_sql(expect=expect, response=response)

        except Exception as e:
            self.logs.error(f'测试异常!断言异常信息:{e}')
        if flag==0:
            self.logs.error(f'测试成功!')
            assert True
        else:
            self.logs.error(f'测试失败')
            assert False

    def contains(self,expect:dict,response:dict):
        """
        先判断{'msg': '登陆成功'}中的key是否在响应值response中存在,
        存在再判断响应值中的key对应的value是否包含了预期的value:登陆成功
        :param expect: 预期结果
        :param response: 实际响应值
        :return:
        """
        # 断言标识flag
        flag=0
        for key,value in expect.items():
            if self.select_node(res=response,node=key):
                # result是从返回值response中查找key(如msg)对应的值
                result=self.select_node(node=key,res=response)
                result=str(result) if isinstance(result,int) else result
                value=str(value) if isinstance(value,int) else value
                if value in result:
                    self.logs.info(f'contains断言成功!实际结果:{key}:{result} 包含 预期结果:{key}:{value}.')
                else:
                    flag+=1
                    allure.attach(body=f'contains断言失败!实际结果:{key}:{result} 不包含 预期结果:{key}:{value}.',name=f'contains的预期结果:{key}:{value}断言失败')
                    self.logs.error(f'contains断言失败!实际结果:{key}:{result} 不包含 预期结果:{key}:{value}.')
            else:
                flag += 1
                allure.attach(body=f'contains断言失败!实际结果不存在节点: {key}! 请检查请求过程或响应结果',
                              name=f'contains的预期结果:{key}:{value}断言失败,实际结果不存在节点: {key}!')
                self.logs.error(f'contains断言失败!实际结果不存在节点: {key}! 请检查请求过程或响应结果')
        return flag

    def equals(self,expect:dict,response:dict):
        """
                先判断{'msg': '登陆成功'}中的key是否在响应值response中存在,
                存在再判断响应值中的key对应的value和预期的value:登陆成功完全相等
                :param expect: 预期结果
                :param response: 实际响应值
                :return:
                """
        # 断言标识flag
        flag = 0
        for key, value in expect.items():
            if self.select_node(res=response, node=key):
                # result是从返回值response中查找key(如msg)对应的值
                result = self.select_node(node=key, res=response)
                result = str(result) if isinstance(result, int) else result
                value = str(value) if isinstance(value, int) else value
                if value == result:
                    self.logs.info(f'equals断言成功!实际结果:{key}:{result} 等于 预期结果:{key}:{value}.')
                else:
                    flag += 1
                    self.logs.error(f'equals断言失败!实际结果:{key}:{result} 不等于 预期结果:{key}:{value}.')
            else:
                flag += 1
                self.logs.error(f'equals断言失败!实际结果不存在节点: {key}! 请检查请求过程或响应结果')
        return flag

    def unequals(self,expect:dict,response:dict):
        # 断言标识flag
        flag = 0
        for key, value in expect.items():
            if self.select_node(res=response, node=key):
                # result是从返回值response中查找key(如msg)对应的值
                result = self.select_node(node=key, res=response)
                result = str(result) if isinstance(result, int) else result
                value = str(value) if isinstance(value, int) else value
                if value != result:
                    self.logs.info(f'unequals断言成功!实际结果:{key}:{result} 不等于 预期结果:{key}:{value}.')
                else:
                    flag += 1
                    self.logs.error(f'unequals断言失败!实际结果:{key}:{result} 等于 预期结果:{key}:{value}.')
            else:
                flag += 1
                self.logs.error(f'unequals断言失败!实际结果不存在节点: {key}! 请检查请求过程或响应结果')
        return flag

    def select_node(self,node,res):
        """
        :param node: 用于查询json格式语句某一个值,采用层级遍历
        :param res: 需要查询的语句
        :return: 查询结果或False
        """
        result=jsonpath.jsonpath(res,f'$..{node}')
        if result:
            return result[0] if len(result)==1 else result
        else:
            return result
    def assert_sql(self,expect:dict,response:dict):
        """
        数据库断言逻辑:
        比如执行了用户新增接口操作,用户新增数据存储在数据库中
        本断言实际就是执行查询(已完成新增用户操作的)数据库,看看是否能查询成功到预期结果数据
        查询成功,断言成功
        用例sql断言示例:
        - db: {'sql':'SELECT * FROM message'}
        :param expect:
        :param response:
        :return:
        """
        for key,value in expect.items():
            flag=0
            result=self.consql.ass_serch(value)
            if result:
                self.logs.info(f'数据库断言成功,断言语句:{value} 断言结果:{result}')
            else:
                flag+=1
                self.logs.error(f'数据库断言失败!无法查询到结果!断言语句:{value}')


if __name__ == '__main__':
    yo=YamlOpertion()
    ast=Assertions()
    validation=yo.read_yaml(key='validation',filepath='Login',filename='login_data.yml')
    res={"error_code":None,"a":{"msg":"登录成功"},"msg_code":200,"orgId":"4140913758110176843","token":"D9F6eD8DDdfCfd5aae2aDBCeA53aC","userId":"9998812396029508725"}
    a=res.keys()
    print(a,type(a))

